
#import "CABleDiscovery.h"


NSString * const CANAME_IDENTIFY = @"SR01";


@interface CABleDiscovery () <CBCentralManagerDelegate, CBPeripheralDelegate>

@property(strong, nonatomic) CBCentralManager *centralManager;
@property(assign, nonatomic) BOOL pendingInit;
@property(assign, nonatomic) LEDISCOVERY_SCANTYPE scanType;   // 扫描时的连接模式



@end

@implementation CABleDiscovery
{
    CBUUID *_otaMainServiceUUID;  // ota 主服务
}

+ (instancetype) sharedInstance
{
	static CABleDiscovery *this	= nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        this = [[CABleDiscovery alloc] init];
    });
	return this;
}

+ (CBUUID*) sigUUIDToCBUUID:(uint16_t)UUID
{
    uint8_t b[2] = { (UUID >> 8) & 0xff, UUID & 0xff };
    return [CBUUID UUIDWithData:[NSData dataWithBytes:b length:2]];
}

+ (uint16_t) sigUUIDFromCBUUID:(CBUUID*)UUID
{
    const uint8_t* b = UUID.data.bytes;
    return UUID.data.length == 2 ? (b[0] << 8) | b[1] : (uint16_t) 0;
}

-(void)regist {
    
}

-(instancetype)init
{
    self = [super init];
    if (self)
    {
        _pendingInit = YES;
        _centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()];

        _foundPeripherals = [[NSMutableArray alloc] init];
        _otaMainServiceUUID = [[self class] sigUUIDToCBUUID:SPOTA_SERVICE_UUID];

        _cidArray = @[
            @[@(0XA5), @(0X0D) ], // 日本
            @[@(0XAD), @(0X0D) ],  // sr23心电
        ]; // 默认值,也可外部赋值
        
	}
    return self;
}

-(void)stconnectPeripheralTimeout:(id)sender {
    
}

- (void) dealloc
{
    // We are a singleton and as such, dealloc shouldn't be called.
//    assert(NO);
}


- (void) loadSavedDevices
{
	NSArray	*storedDevices	= [[NSUserDefaults standardUserDefaults] arrayForKey:@"StoredDevices"];

	if (![storedDevices isKindOfClass:[NSArray class]]) {
        DebugNSLog(@"No stored array to load");
        return;
    }
     
    for (id deviceUUIDString in storedDevices)
    {
        
        if (![deviceUUIDString isKindOfClass:[NSString class]])
            continue;
        CFUUIDRef uuid = CFUUIDCreateFromString(NULL, (CFStringRef)deviceUUIDString);
        if (!uuid)
            continue;
        [_centralManager retrievePeripheralsWithIdentifiers:[NSArray arrayWithObject:(__bridge id)uuid]];
    }
}


- (void) centralManager:(CBCentralManager *)central didRetrieveConnectedPeripherals:(NSArray *)peripherals
{
//	CBPeripheral	*peripheral;
//	
//	/* Add to list. */
//	for (peripheral in peripherals) {
//		[central connectPeripheral:peripheral options:nil];
//	}
//	[discoveryDelegate discoveryDidRefresh];
}



- (void) centralManager:(CBCentralManager *)central didRetrievePeripheral:(CBPeripheral *)peripheral
{
	[central connectPeripheral:peripheral options:nil];
//    [_discoveryDelegate stdiscoveryDidRefresh];
}

//delete the stored device uuid in list
- (void) centralManager:(CBCentralManager *)central didFailToRetrievePeripheralForUUID:(CFUUIDRef)UUID error:(NSError *)error
{
	/* Nuke from plist. */
//	[DeviceRecordManager removeSavedDevice:UUID];
    
}



#pragma mark -
#pragma mark Discovery

/// 开始扫描
- (void) startScanning:(LEDISCOVERY_SCANTYPE)scanType
            ScanOption:(NSDictionary * _Nullable)options
{
    _scanType = scanType;
    [self stopScanning];
    [_foundPeripherals removeAllObjects];
    
    CBUUID * deviceUUid = [CBUUID UUIDWithString:CASERVICE_UUID_DATA];
    NSArray	*uuidArray	= @[deviceUUid];//[NSArray arrayWithObjects:
                           //[CBUUID UUIDWithString:kBatteryServiceUUIDString],
//                           [CBUUID UUIDWithString:kSetDeviceAlertServiceUUIDString],
                           //[CBUUID UUIDWithString:kSetMobileAlertServiceUUIDString],
//                           [CBUUID UUIDWithString:serviceUUIDString],
//                           nil];
    if (!options) {
        options = @{ CBCentralManagerScanOptionAllowDuplicatesKey : @NO };

    }
    self.isRefreahing = YES;
	[_centralManager scanForPeripheralsWithServices:nil options:options];
//    [_centralManager retrieveConnectedPeripheralsWithServices:uuidArray];

}


- (void) stopScanning
{
    if (_centralManager != nil) {
        [_centralManager stopScan];
        
    }
    self.isRefreahing = NO;
}

-(void)ousideSetCurrentService:(CABLeService * _Nullable)service
{
    _currentService = service;
}

/// 扫描发现设备
/// @param central 蓝牙中心
/// @param peripheral 扫描到外设
/// @param advertisementData 外谁的信息
/// @param RSSI 蓝牙信号
- (void)centralManager:(CBCentralManager *)central
 didDiscoverPeripheral:(CBPeripheral *)peripheral
     advertisementData:(NSDictionary *)advertisementData
                  RSSI:(NSNumber *)RSSI
{
//    peripheral.identifier.UUIDString // 设备标识
    NSString *advertisementName = [advertisementData objectForKey:@"kCBAdvDataLocalName"];
    NSString *periName = advertisementName;
//    NSString *macString = nil;
//    if (advertisementName.length>=6) {
//        macString = [advertisementName substringWithRange:NSMakeRange(advertisementName.length -6, 6)];
//    }
    
    __block BOOL canAdd = NO;
    if ([advertisementName containsString:CANAME_IDENTIFY]) {
        DebugNSLog(@"蓝牙发现外设:  advertisementName: %@",advertisementName);
        canAdd = YES;
    }

    
    //过滤指定设备 临时关闭

    NSArray *services = [advertisementData valueForKey:CBAdvertisementDataServiceUUIDsKey];
    NSArray *servicesOvfl = [advertisementData valueForKey:CBAdvertisementDataOverflowServiceUUIDsKey];
    
//    if ([advertisementName containsString:@"7BE5"]) {
       
//    }
    
    
    
    if ([services containsObject:_otaMainServiceUUID]
        || [servicesOvfl containsObject:_otaMainServiceUUID]) {
        DebugNSLog(@"%@ [%@]: Found SUOTA service UUID in advertising data", peripheral.name, peripheral.identifier.UUIDString);
//        DebugNSLog(@"advertisementData = %@", advertisementData);
        canAdd = YES;
    } else {
        canAdd = NO; //不能ota的不加列表
    }
    
    if (!advertisementName.length) {// 无广播名不加
        canAdd = NO;
    }
    
    if (canAdd)
    {
        // mac 地址拼接
        NSString *macString = nil;
        NSData * manufacturerData = advertisementData[@"kCBAdvDataManufacturerData"];
        //加入发现数组
        CABLeService *service = [[CABLeService alloc] initWithPeripheral:peripheral controller:nil];
        
        Byte * manufacturerBybtes =  (Byte *)(manufacturerData.bytes);
        
        if(manufacturerData.length < 2) {
            return;
        }
        
        NSArray<NSArray<NSNumber *> * > *cidArray = self.cidArray;
        BOOL newAnaly = NO;
        for (NSArray<NSNumber *> * cid in cidArray) {
            if (manufacturerBybtes[0] == [cid[0] unsignedCharValue] 
                && manufacturerBybtes[1] == [cid[1] unsignedCharValue])
            {
                newAnaly = YES;
                break;
            }
        }
        
        if (newAnaly) {
            DebugNSLog(@"新广播包解析 %@", advertisementName);
            if(manufacturerData.length < 19) {
                return;
            }
            // 日本戒指 广播包不同
            NSString *macString = [NSString  stringWithFormat:@"%.2X:%.2X:%.2X:%.2X:%.2X:%.2X", manufacturerBybtes[2], manufacturerBybtes[3], manufacturerBybtes[4], manufacturerBybtes[5], manufacturerBybtes[6], manufacturerBybtes[7]];
            service.macAddress = macString;
            
            service.deviceColor = (NSUInteger)(manufacturerBybtes[8] & 0XFF); // 颜色
            service.deviceSize = manufacturerBybtes[9] & 0xFF; // 尺寸
            
            uint8_t isCharging = (manufacturerBybtes[10] >> 7) & 0X01; // 充电状态
            uint8_t batteryLevel = manufacturerBybtes[10] & 0X7F;  // 电量
            
            NSInteger chipType = (manufacturerBybtes[11] >> 4) & 0XFF; // 主芯片型号
            NSUInteger deviceGeneration = (manufacturerBybtes[11]) & 0X0F; // 迭代版本
            service.mainChipType = chipType;
            service.deviceGeneration = deviceGeneration;
            service.scanIsCharge = @(isCharging);
            service.scanBatteryLevel = @(batteryLevel);
            service.advDataLocalName = advertisementName;
            service.rssi = RSSI;
            
            service.cid = manufacturerBybtes[1];
            service.cid = (service.cid << 8)& 0XFFFF + manufacturerBybtes[0];
            // sn
            NSString *snString = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x", manufacturerBybtes[12],
                                  manufacturerBybtes[13],
                                  manufacturerBybtes[14],
                                  manufacturerBybtes[15],
                                  manufacturerBybtes[16],
                                  manufacturerBybtes[17]];
            long long snNUmber = [snString longLongValue];
            snString = [NSString stringWithFormat:@"%lld", snNUmber];
            service.snString = snString;
            
        } else {
            // sr09 sr23 sr03 sr23(0.3.0前)协议
            if (manufacturerData.length >= 4) {
                NSData *macDataLowBit = [manufacturerData subdataWithRange:NSMakeRange(0, 4)];
                
                Byte *byte = (Byte *)[macDataLowBit bytes];
                macString = [NSString  stringWithFormat:@"%.2X:%.2X:%.2X:%.2X", byte[0], byte[1], byte[2], byte[3]];
                if (advertisementName.length>=4) {
                    NSString *macString_high = [advertisementName substringWithRange:NSMakeRange(advertisementName.length - 4, 4)];
                    NSMutableString *mutStr = [NSMutableString stringWithString:macString_high];
                    [mutStr insertString:@":" atIndex:2];
                    macString = [NSString stringWithFormat:@"%@:%@", macString, mutStr];

                }
            }
           
            BOOL iswirenessCharge = NO;
            if ([advertisementName containsString:@"w"] || [advertisementName containsString:@"W"]) {
                // 无线充电版本
                iswirenessCharge = YES;
            }

            if (manufacturerData.length >= 6) {
                // 解析颜色和尺寸
                Byte *byte = (Byte *)[manufacturerData bytes];
                service.deviceColor = (NSUInteger)(byte[4]); // 颜色
                service.deviceSize = byte[5] & 0xFF; // 尺寸
            }
            
            if (manufacturerData.length >= 8)
            {
    //            if([macString containsString:@"27:6C"]){
    //
    //            }
                Byte *byte = (Byte *)[manufacturerData bytes];
    //            byte[6]; // 充电状态和电量
                uint8_t b6 = byte[6];
                uint8_t isCharging = (b6 >> 7) & 0X01; // Is device charging. YES = charging
                uint8_t batteryLevel = b6 & 0X7F;  // battery level,range in 0-100
                
                uint8_t b7 = byte[7];
                NSInteger chipType = (byte[7] >> 4) & 0XFF; // 主芯片型号
                NSUInteger deviceGeneration = (byte[7]) & 0X0F; // 迭代版本
                service.mainChipType = chipType;
                service.deviceGeneration = deviceGeneration;
                service.scanIsCharge = @(isCharging);
                service.scanBatteryLevel = @(batteryLevel);
            }
            
            
            service.isWirenessCharge = @(iswirenessCharge);
            service.advDataLocalName = advertisementName;
            service.macAddress = macString;
            service.rssi = RSSI;
            
        }
        
     
        
        
        if (_scanType == LEDISCOVERY_SCANTYPE_RECONECT
            || _scanType == LEDISCOVERY_SCANTYPE_AUTOCONNECT)
        {
            // 第一次自动扫描连接过
            // 发现是上一次连接并异常断开的设备, 直接重连
            // && _currentService.isManualDisconnect == NO
            if ([_currentService.peripheral.identifier.UUIDString isEqual:service.peripheral.identifier.UUIDString]
               )
            {
                if (_currentService.peripheral != peripheral) {
                    _currentService = service;
                }
                [_centralManager connectPeripheral:_currentService.peripheral options:nil];
            }
            
            // 第一次连接设备 直接连接
            if (_currentService == nil) {
                // 直接连接
                _currentService = service;
                [_centralManager connectPeripheral:_currentService.peripheral options:nil];
            }
            [_centralManager stopScan]; //停止扫描
            return;
            
        } else if (_scanType == LEDISCOVERY_SCANTYPE_LISTCHOOSE) {
            
            if (service.macAddress != nil || YES) {
                //加入发现数组
                [self addToFoundService:service AdvertisementData:advertisementData];
                if ([_discoveryDelegate respondsToSelector:@selector(stdiscoveryDidRefresh:)]) {
                    [_discoveryDelegate stdiscoveryDidRefresh:[NSArray arrayWithArray:_foundPeripherals]];
                }
            }
          
        }
        
    }
}

-(void)addToFoundService:(CABLeService *)service AdvertisementData:(NSDictionary *)advertisementData
{
    BOOL canAdd = YES;
    // 防止重复加入
    for (CABLeService *s in _foundPeripherals) {
        if (service.peripheral == s.peripheral) {
            if ([service.advDataLocalName isEqualToString:s.advDataLocalName]) {
                canAdd = NO;
            } else {
                [_foundPeripherals removeObject:s];
                canAdd = YES;
                break;
            }
            break;
        }
        
    }
    
    if (canAdd) {
        [_foundPeripherals addObject:service];
    }
    
}


-(void)sendData:(NSData *)data type:(CBCharacteristicWriteType)type
{
    //认准了状态是Connected的那个也就可以了，目前没有同时连接多个设备的需求。
//    [_currentService sendValue:_currentService.peripheral sendData:data type:type];
    
}

#pragma mark -
#pragma mark retrievePeripheral

- (void) retrievePeripheral:(NSString *)uuid
{
    if (uuid != nil) {
        CFUUIDRef uuidRef = CFUUIDCreateFromString(NULL, (__bridge CFStringRef)uuid);
        NSArray *uuids = [NSArray arrayWithObject:(__bridge id)uuidRef];
        [_centralManager retrievePeripheralsWithIdentifiers:uuids];
    }
    
}

- (void)centralManager:(CBCentralManager *)central didRetrievePeripherals:(NSArray *)peripherals
{
    [self.discoveryDelegate stdidRetrievePeripherals:peripherals];
}

#pragma mark -
#pragma mark Connection/Disconnection
/****************************************************************************/
/*						Connection/Disconnection                            */
/****************************************************************************/
- (void) connectPeripheral:(CABLeService*)keyService
{
    //停止扫描
    [_centralManager stopScan];
    
    if (keyService == _currentService) {
        if ( _currentService.peripheral.state == CBPeripheralStateConnected) {
            // 已连接
            if ([_peripheralDelegate respondsToSelector:@selector(stkeyFobServiceDidConnectPeripheral:)]) {
                [_peripheralDelegate stkeyFobServiceDidConnectPeripheral:_currentService];
                return;
            }
        } else {
            [_centralManager connectPeripheral:_currentService.peripheral options:nil];
            return;
        }
       
    } else {
        
        if (_currentService.peripheral.state == CBPeripheralStateConnected) {
            [_centralManager cancelPeripheralConnection:_currentService.peripheral];
            DebugNSLog(@"主动断开 %s %d", __func__, __LINE__);
           
        }
        _currentService = keyService;
        
        if (keyService.peripheral.state != CBPeripheralStateConnected) {
            [_centralManager connectPeripheral:keyService.peripheral options:nil];
            [self performSelector:@selector(stconnectPeripheralTimeout:) withObject:keyService afterDelay:900.0f];
        }
    }
    
	
}

//-(void)

- (void)connectPeripheralTimeout:(id)obj
{
    CABLeService *p = obj;
    if (!(p.peripheral.state == CBPeripheralStateConnected)) {
        [_discoveryDelegate stconnectPeripheralTimeout:p];
    }
}

- (void) disconnectPeripheral:(CABLeService*)keyService
{
//    for (LeKeyFobService *s in self.connectedServices) {
//        if (s.peripheral.name == keyService.peripheral.name) {
//            s.isManualDisconnect = YES;
//        }
//    }
    
    if (_currentService == keyService) {
        _currentService.isManualDisconnect = YES;
    }
    
    if (![_foundPeripherals containsObject:_currentService] && _currentService != nil)
    {
        [_foundPeripherals addObject:_currentService];
    }
    if (keyService.peripheral) {
        [_centralManager cancelPeripheralConnection:keyService.peripheral];
        DebugNSLog(@"主动断开 %s %d", __func__, __LINE__);

    }
    _currentService = nil;
}

- (void)cancelAllReconnect
{
//    for (LeKeyFobService *s in self.connectedServices) {
        if (!(_currentService.peripheral.state == CBPeripheralStateConnected)) {
            [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(stconnectPeripheralTimeout:) object:_currentService.peripheral];
        }
//    }
    for (CBPeripheral *p in self.foundPeripherals) {
        if (!(p.state ==CBPeripheralStateConnected)) {
            [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(stconnectPeripheralTimeout:) object:p];
        }
    }

}


- (void) centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
//	LeKeyFobService	*service	= nil;
//	BOOL isExist = NO;
    
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(stconnectPeripheralTimeout:) object:peripheral];
    
    
    if ([_currentService.peripheral.identifier.UUIDString isEqualToString:peripheral.identifier.UUIDString]) {
        
        if (_currentService.peripheral.state == CBPeripheralStateConnected){
            [_currentService setPerpheralDelegate:_peripheralDelegate];
            [_currentService start]; // 开始业务
            
            //代理回调
            [_peripheralDelegate stkeyFobServiceDidChangeStatus:_currentService];
            [_peripheralDelegate stkeyFobServiceDidConnectPeripheral:_currentService];
//            [_discoveryDelegate stdiscoveryDidRefresh];
            
        } else {

            DebugNSLog(@"lzp 异常连接 1!!!");
        }
        
    } else {
        // 不是上次要连接的设备
        DebugNSLog(@"lzp 异常连接 2!!!");
    }

}


/// 蓝牙连接失败
/// @param central
/// @param peripheral
/// @param error
- (void) centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
    DebugNSLog(@"Attempted connection to peripheral %@ failed: %@", [peripheral name], [error localizedDescription]);
    if ([_peripheralDelegate respondsToSelector:@selector(stkeyFobServiceDidFailConnectPeripheral:Error:)]) {
        [_peripheralDelegate stkeyFobServiceDidFailConnectPeripheral:peripheral Error:error];
    }
}


/// 扫描到蓝牙设备
/// @param central
/// @param peripheral
/// @param error
- (void) centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
    if ([_currentService peripheral] != peripheral) {
        return;
    }
    
    if ([_currentService peripheral] == peripheral) {
        [_currentService stopRssiTimer];
        
        if (_currentService.isManualDisconnect
            && !_currentService.isExceptional)
        {
            /*
             如果是手动断开的，把它从services里面删除的同时，
             要把它加回到foundPeripherals里面
             以保证用户可以重新手动连接
             */
            [self addToFoundService:_currentService AdvertisementData:nil];
            [_currentService setPerpheralDelegate:nil];
        }
        else
        {
            //如果是异常断开，要准备重连
            _currentService.isExceptional = YES;
            [_currentService setPerpheralDelegate:nil];
            DebugNSLog(@"异常断开 error:%@", error);
            //异常断开的动画
            //3.通知代理
            if ([self.discoveryDelegate respondsToSelector:@selector(stabnormalDisconnect:)]) {
                [self.discoveryDelegate stabnormalDisconnect:self];
            }
            
        }
        DebugNSLog(@"didDisconnectPeripheral!!!!!!!");
        [_peripheralDelegate stkeyFobServiceDidChangeStatus:_currentService];
        [_peripheralDelegate stkeyFobServiceDidDisconnectPeripheral:_currentService];
        NSDictionary * info = [NSDictionary dictionaryWithObjectsAndKeys: peripheral.name,@"UUID", nil];
        [[NSNotificationCenter defaultCenter] postNotificationName:nDidDisconnect object:nil userInfo:info];
        
    } /*if ([_currentService peripheral] == peripheral)*/
   
    
    // norify ota SROtaManager
    [[NSNotificationCenter defaultCenter] postNotificationName:CABluetoothManagerDisconnectedFromDevice object:peripheral];
//    [discoveryDelegate discoveryDidRefresh];
    
}


/// 清空所有发现和连接过的设备
- (void) clearDevices
{
    [_foundPeripherals removeAllObjects];
    
    if (_currentService.peripheral.state == CBPeripheralStateConnected) {
        [_centralManager cancelPeripheralConnection:_currentService.peripheral];
        DebugNSLog(@"主动断开 %s %d", __func__, __LINE__);

        [_currentService setPerpheralDelegate:nil];
        _currentService = nil;
    }
    
}

- (CBManagerState)deviceBleCenterState
{
    return  [_centralManager state];
}

- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
    static CBManagerState previousState = -1;
    /* ios 10.0
     CBManagerStateUnknown = 0,
     CBManagerStateResetting,
     CBManagerStateUnsupported,
     CBManagerStateUnauthorized,
     CBManagerStatePoweredOff,
     CBManagerStatePoweredOn,
     */
    DebugNSLog(@"手机蓝牙状态: %ld", (long)[_centralManager state]);
	switch ([_centralManager state]) {
        case CBManagerStateUnsupported:
        {
            //不支持
            break;
        }
		case CBManagerStatePoweredOff:
		{
            [self clearDevices];
//            [_discoveryDelegate stdiscoveryDidRefresh];
            
			/* Tell user to power ON BT for functionality, but not on first run - the Framework will alert in that instance. */
            if (previousState != -1) {
//                [_discoveryDelegate stdiscoveryStatePoweredState:NO];
                if ([_discoveryDelegate respondsToSelector:@selector(stabnormalDisconnect:)]) {
                    [_discoveryDelegate stabnormalDisconnect:nil];

                }
            }
			break;
		}
            
		case CBManagerStateUnauthorized:
		{
			/* Tell user the app is not allowed. */
			break;
		}
            
		case CBManagerStateUnknown:
		{
			/* Bad news, let's wait for another event. */
			break;
		}
            
		case CBManagerStatePoweredOn:
		{
			_pendingInit = NO;
			[self loadSavedDevices];
            
         
            
			break;
		}
            
		case CBManagerStateResetting:
		{
			[self clearDevices];
//            [_discoveryDelegate stdiscoveryDidRefresh];
            if ([_peripheralDelegate respondsToSelector:@selector(stkeyFobServiceDidReset)]) {
                [_peripheralDelegate stkeyFobServiceDidReset];
            }
            
			_pendingInit = YES;
			break;
		}
	}
    
    previousState = [_centralManager state];
    if ([_discoveryDelegate respondsToSelector:@selector(stdiscoveryStatePoweredState:)]) {
        [_discoveryDelegate stdiscoveryStatePoweredState:previousState];
    }
    DebugNSLog(@"sdk 回调 centralManagerDidUpdateState state =%ld", (long)previousState);
}

//-(void)centralManager:(CBCentralManager *)central willRestoreState:(NSDictionary<NSString *,id> *)dict
//{
//
//}
@end
